在前面的試作過程中,我們很陽春的刻了一個臨時的後台畫面來使用,然後每換一個頁面,我們就得複製一整個包含選單的組件檔案來修改,如果現在我改了後端的路由,那前端的路徑也肯定要改,但因為選單的部份是五六個後端頁面都有的,所以我們得改完全部的頁面才行,日後如果後台增加到二三十個頁面時,那這修改的量會讓你胃食道逆流到海角天邊去。
使用Vue做為前端框架,有一件很方便的事就是自訂組件,並把組件以標籤的方式來使用,這會大大的提高頁面程式碼的可讀性,也可降低程式碼的重覆,並讓後續的維護和擴充變得容易許多。
之前的管理後台左側選單有點老套,現在我們已經確認了後端的資料溝通方式了,所以也不用擔心資料傳不出來的問題,在設計上可以大膽一點,我們讓選單是貼在左側的滿版長條,右側全部空間都拿來顯示內容,
resources\js\Layouts\AuthenticatedLayout.vue
....略
<!-- Primary Navigation Menu -->
<!-- 把區塊寬度改為全寬滿版 -->
<div class="w-full mx-auto px-4 sm:px-6 lg:px-8">
....略
<!-- Page Heading -->
<!--調整header的z-index 要顯示出header的底部陰影線-->
<header class="bg-white shadow relative z-20" v-if="$slots.header">
<!-- 把區塊寬度改為全寬滿版 -->
<div class="w-full mx-auto py-6 px-4 sm:px-6 lg:px-8">
<slot name="header" />
</div>
</header>
....略
<!-- Page Content -->
<!--調整main的z-index 讓main在header之下-->
<main class="relative z-10">
<slot />
</main>
resources\js\Pages\Backstage\Backstage.vue
<AuthenticatedLayout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">管理中心</h2>
</template>
<!--後台主內容區-->
<div class="w-full bg-white flex">
<!--左側選單-->
<div class="w-48 max-w-96 bg-black text-white py-8 px-2 shadow-lg h-[calc(100vh_-_138px)]">
<Link :href="route('backstage.banks')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理題庫
</Link>
<Link :href="route('backstage.quizzes')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理試卷
</Link>
<Link :href="route('backstage.tests')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理測驗
</Link>
<Link :href="route('backstage.groups')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理群組
</Link>
</div>
<!--右側內容區-->
<div class="w-5/6 p-4 flex flex-wrap">
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-green-400">
題庫:
</div>
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-sky-400">
試卷:
</div>
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-yellow-400">
測驗:
</div>
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-orange-400">
群組:
</div>
</div>
</div>
</AuthenticatedLayout>
這個後台頁面是基於 Breeze 的 AuthenticatedLayout 組件,我們可以在這個基礎上加入我們自己的組件,一個是左側選單,一個是右側的內容區,我們打算先把左側選單獨立出來成為一個組件。
在 resources\js\Layouts
目錄下建立一個 BackstageLeftMenu.vue,並將選單的程式碼搬過去
resources\js\Layouts\BackstageLeftMenu.vue
記得要引入 inertia 的 Link 組件
<script setup>
import { Link } from "@inertiajs/inertia-vue3";
</script>
<template>
<!--左側選單-->
<div class="w-48 max-w-96 bg-black text-white py-8 px-2 shadow-lg h-[calc(100vh_-_138px)]">
<Link :href="route('backstage.banks')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理題庫
</Link>
<Link :href="route('backstage.quizzes')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理試卷
</Link>
<Link :href="route('backstage.tests')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理測驗
</Link>
<Link :href="route('backstage.groups')"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
管理群組
</Link>
</div>
</template>
我們可以在原本的檔案位置使用 <BackstageLeftMenu />
來引入這個組件,但這又回到老問題,每一個後台頁面都要再放一次這個組件,而且還要考慮每個頁面的選單項目是那個;
換個方向想,既然這個選單是後台所有頁面都必然存在的,那它當然可以視為是整體 layout 的一部份,這也是為什麼我要把它放在 layout 目錄下的原因;
那就把選單放在 AuthenticatedLayout 中吧:
<!-- Page Content -->
<main class="relative z-10">
<!--後台主內容區-->
<div class="w-full bg-white flex">
<!--左側選單組件放在這-->
<BackstageLeftMenu />
<!--右側的內容會由slot來引入-->
<slot />
</div>
</main>
resources\js\Pages\Backstage\Backstage.vue 內容少很多,可以專注在右側內容區上
<AuthenticatedLayout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">管理中心</h2>
</template>
<!--右側內容區-->
<div class="w-5/6 p-4 flex flex-wrap">
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-green-400">
題庫:
</div>
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-sky-400">
試卷:
</div>
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-yellow-400">
測驗:
</div>
<div class="w-1/2 border rounded-xl flex p-4 h-48 bg-orange-400">
群組:
</div>
</div>
</AuthenticatedLayout>
除了這種選單類的可以拆之外,像是一些 css 比較複雜或是有可能多次重覆使用的標籤元件,也都可以拆,比如選單中的每個項目都有比較複雜的 css,之後要增加項目時又要再複製一堆一樣的 class,這時也可以把這個項目拆成組件,然後可以由組件來傳入相關的參數;
由於自建組件的狀況會很多,為了方便管理,我們建立一個 QuizComponents 資料夾來管理我們自己建立的這些組件,當然,多到一個程度,可以再開子資料夾來做分類:
resources\js\QuizComponents\MenuItem.vue
<script setup>
import { Link } from "@inertiajs/inertia-vue3";
//定義可以傳入的參數
defineProps({
route: String,
});
</script>
<template>
<Link :href="route"
class="block my-2 py-2 hover:bg-slate-50 hover:text-slate-900 text-center text-xl">
<!--提供插槽供外部使用-->
<slot />
</Link>
</template>
然後把選單項目組件引入到 resources\js\Layouts\BackstageLeftMenu.vue
<script setup>
import MenuItem from "@/QuizComponents/MenuItem.vue";
</script>
<template>
<!--左側選單-->
<div class="w-48 max-w-96 bg-black text-white py-8 px-2 shadow-lg h-[calc(100vh_-_138px)]">
<MenuItem :route="route('backstage.banks')">管理題庫</MenuItem>
<MenuItem :route="route('backstage.quizzes')">管理試卷</MenuItem>
<MenuItem :route="route('backstage.tests')">管理測驗</MenuItem>
<MenuItem :route="route('backstage.groups')">管理群組</MenuItem>
</div>
</template>
現在的選單看起來是不是好讀多了?
以此類推,可以先把其他的後端頁面原本的選單html碼整理一下,你會得到一組清爽的前端頁面檔案。
今天先這樣,前端頁面的拆解並不是這麼單純的,除了版型的調整,我們還得重新定義前端的邏輯,這部份會使用上狀態管理,我們明天再來說明。